from ply.yacc import yacc
from Excute.astNode import *
from .lexAna import tokens, lexer


def p_program(p):
    '''program : program_element_list'''
    p[0] = Program(Block(p[1]))


def p_program_element_list(p):
    '''program_element_list : program_element_list program_element
                            | program_element'''
    if len(p) == 3:
        p[0] = p[1] + [p[2]]
    else:
        p[0] = [p[1]]


def p_program_element(p):
    '''program_element : declaration
               | statement'''
    p[0] = p[1]


def p_declaration(p):
    '''declaration : variable_declaration
                   | function_declaration
                   | prototype_declaration'''
    p[0] = p[1]


def p_variable_declaration(p):
    '''variable_declaration : VAR IDENTIFIER EQUALS expression SEMI
                            | VAR IDENTIFIER SEMI'''
    if len(p) == 6:
        p[0] = VariableDeclaration(p[2], p[4])
    else:
        p[0] = VariableDeclaration(p[2])


def p_function_declaration(p):
    '''function_declaration : FUNCTION IDENTIFIER LPAREN parameters RPAREN LBRACE function_body RBRACE'''
    p[0] = FunctionDeclaration(p[2], p[4], Block(p[7]))


def p_parameters(p):
    '''parameters : parameters COMMA IDENTIFIER
                  | IDENTIFIER
                  | empty'''
    if len(p) == 4:
        p[0] = p[1] + [p[3]]
    elif len(p) == 2:
        if p[1] is None:
            p[0] = []
        else:
            p[0] = [p[1]]
    else:
        p[0] = []


def p_function_body(p):
    '''function_body : function_body program_element
                     | empty'''
    if len(p) == 3:
        p[0] = p[1] + [p[2]]
    else:
        p[0] = []


def p_return_statement(p):
    '''return_statement : RETURN expression SEMI'''
    p[0] = ReturnStatement(p[2])


def p_empty(p):
    'empty :'
    pass


def p_prototype_declaration(p):
    '''prototype_declaration : PROTOTYPE IDENTIFIER LBRACE prototype_body RBRACE'''
    p[0] = PrototypeDeclaration(p[2], p[4])


def p_prototype_body(p):
    '''prototype_body : function_body'''
    p[0] = Block(p[1])


def p_statement(p):
    '''statement : expression_statement
                 | assign_statement
                 | if_statement
                 | loop_statement
                 | try_catch_statement
                 | return_statement'''
    p[0] = p[1]


def p_expression_statement(p):
    '''expression_statement : expression SEMI'''
    p[0] = ExpressionStatement(p[1])


def p_assign_statement(p):
    '''assign_statement : basic_expression_without_not EQUALS expression SEMI'''
    p[0] = AssignStatement(p[1], p[3])


def p_if_statement(p):
    '''if_statement : IF LPAREN expression RPAREN LBRACE function_body RBRACE
                    | IF LPAREN expression RPAREN LBRACE function_body RBRACE ELSE LBRACE function_body RBRACE'''
    if len(p) == 8:
        p[0] = IfStatement(p[3], Block(p[6]))
    else:
        p[0] = IfStatement(p[3], Block(p[6]), Block(p[10]))


"""
def p_loop_statement(p):
    '''loop_statement : WHILE LPAREN expression RPAREN LBRACE function_body RBRACE
                      | FOR LPAREN expression SEMI expression SEMI expression RPAREN LBRACE function_body RBRACE'''
    # 实现略，根据具体逻辑填充
"""


def p_while_statement(p):
    '''loop_statement : WHILE LPAREN expression RPAREN LBRACE function_body RBRACE'''
    p[0] = LoopStatement(p[3], Block(p[6]))


# 对于FOR循环的实现，你可以将其分解为初始化、条件和更新步骤，但这取决于你的语言具体如何定义FOR循环。


def p_try_catch_statement(p):
    '''try_catch_statement : TRY LBRACE function_body RBRACE CATCH LPAREN IDENTIFIER RPAREN LBRACE function_body RBRACE'''
    p[0] = TryCatchStatement(Block(p[3]), Block(p[10]))


# 优先级定义
precedence = (
    ('left', 'LPAREN', 'ARROW', 'LBRACKET'),
    ('left', 'PLUS', 'MINUS'),
    ('left', 'TIMES', 'DIVIDE', 'MOD'),
    ('left', 'GT', 'LT', 'GE', 'LE', 'EQ', 'NEQ'),
    ('left', 'BITAND', 'BITOR'),
    ('right', 'NOT'),
    ('left', 'OR'),
    ('left', 'AND'),
)


# 解析规则
def p_expression(p):
    '''expression : bool_expression
                  | expression AND bool_expression
                    '''
    if len(p) == 2:
        p[0] = p[1]
    else:
        p[0] = BinaryExpression(p[1], p[2], p[3])


def p_compare_expression(p):
    '''compare_expression : number_expression compare_operator number_expression
                          | number_expression'''
    if len(p) == 2:
        p[0] = p[1]
    elif len(p) == 3:
        p[0] = BinaryExpression(p[2], p[1], None)
    else:
        p[0] = BinaryExpression(p[1], p[2], p[3])


def p_bool_expression(p):
    '''bool_expression : compare_expression
                       | bool_expression OR compare_expression
                       '''
    if len(p) == 2:
        p[0] = p[1]
    else:
        p[0] = BinaryExpression(p[1], p[2], p[3])


def p_expression_basic_without_not(p):
    '''basic_expression_without_not : literal
                            | IDENTIFIER
                            | LPAREN expression RPAREN
                            | function_call_expression
                            | chain_expression
                            | list_expression
                            | list_ele'''
    if len(p) == 4:
        p[0] = p[2]  # 对应于括号内的表达式
    else:
        if isinstance(p[1], Node):
            p[0] = p[1]
        else:
            p[0] = Identifier(p[1])


def p_expression_basic(p):
    '''basic_expression : basic_expression_without_not
                        | NOT basic_expression'''
    if len(p) == 3:
        p[0] = BinaryExpression(p[2], p[1], None)  # 对应not表达式
    else:
        p[0] = p[1]


def p_list_expression(p):
    '''list_expression : LBRACKET arguments RBRACKET'''
    p[0] = ListEntity(p[2])  # 假设 ListExpression 是处理列表表达式的类


def p_list_ele(p):
    '''list_ele : list_ele LBRACKET expression RBRACKET
                | IDENTIFIER LBRACKET expression RBRACKET'''
    p[0] = ListElement(p[1], p[3])


def p_expression_ele(p):
    '''ele_expression : basic_expression
                | ele_expression BITAND basic_expression
                | ele_expression BITOR basic_expression
                | ele_expression MOD basic_expression'''
    if len(p) == 2:
        p[0] = p[1]
    else:
        p[0] = BinaryExpression(p[1], p[2], p[3])


def p_expression_term(p):
    '''term : ele_expression
            | term TIMES ele_expression
            | term DIVIDE ele_expression'''
    if len(p) == 2:
        p[0] = p[1]
    else:
        p[0] = BinaryExpression(p[1], p[2], p[3])


def p_number_expression(p):
    '''number_expression : term
                  | number_expression PLUS term
                  | number_expression MINUS term'''
    if len(p) == 2:
        p[0] = p[1]
    else:
        p[0] = BinaryExpression(p[1], p[2], p[3])


def p_typed_binary_expression(p):
    '''expression : expression DOLLAR type DOLLAR binary_operator  bool_expression
                  '''
    p[0] = TypedBinaryExpression(p[1], p[5], p[3], p[6])


def p_binary_operator(p):
    '''binary_operator : PLUS
                       | MINUS
                       | TIMES
                       | DIVIDE'''
    p[0] = p[1]


def p_compare_operator(p):
    '''compare_operator : GT
                        | LT
                        | GE
                        | LE
                        | EQ
                        | NEQ'''
    p[0] = p[1]


def p_type(p):
    '''type : IDENTIFIER'''
    p[0] = p[1]


def p_literal(p):
    '''literal : NUMBER
               | FLOAT
               | STRING'''

    def type_to_string(value):
        if isinstance(value, int):
            return '$int$'
        elif isinstance(value, float):
            return '$float$'
        elif isinstance(value, str):
            return '$string$'

    p[0] = Literal(p[1], type_to_string(p[1]))


def p_function_call_expression(p):
    '''function_call_expression : basic_expression_without_not LPAREN arguments RPAREN'''
    p[0] = FunctionCall(p[1], p[3])


def p_arguments(p):
    '''arguments : arguments COMMA expression
                 | expression
                 | empty'''
    if len(p) == 4:
        p[0] = p[1] + [p[3]]
    elif len(p) == 2 and p[1] is not None:
        p[0] = [p[1]]
    else:
        p[0] = []


def p_chain_expression(p):
    '''chain_expression : basic_expression_without_not ARROW IDENTIFIER'''
    p[0] = ChainExpression(p[1], p[3])


# 错误处理
def p_error(p):
    if p:
        print("Syntax error at token", p)
        # 访问解析器的语法栈
        stack = parser.symstack[::-1]  # 倒序以便从栈底开始查看

        print("Syntax stack:")
        for entry in stack:
            print(f"Type: {entry}")
        # Just discard the token and tell the parser it's okay.
        parser.errok()
    else:
        print("Syntax error at EOF")


parser = yacc()

if __name__ == "__main__":
    # 测试解析器
    def test_parser(input_string):
        result = parser.parse(input_string)
        return result


    # 打印语法树
    def print_nodes(node, depth=0):
        # 检查传入的对象是否是Node的实例
        if isinstance(node, Node):
            print("--" * depth + str(node))
            # 遍历对象的所有属性
            for attr_name in dir(node):
                attr_value = getattr(node, attr_name)
                # 跳过特殊方法和属性
                if not attr_name.startswith('__'):
                    print_nodes(attr_value, depth + 1)
        elif isinstance(node, (list, tuple, set)):
            # 遍历列表、元组或集合
            for item in node:
                print_nodes(item, depth + 1)
        elif isinstance(node, dict):
            # 遍历字典的值
            for key, value in node.items():
                print_nodes(value, depth + 1)


    # 测试示例
    test_code = """
    a+1;
    """
    tree = test_parser(test_code)
    print_nodes(tree)
